//
//
// Tencent is pleased to support the open source community by making tRPC available.
//
// Copyright (C) 2023 Tencent.
// All rights reserved.
//
// If you have downloaded a copy of the tRPC source code from Tencent,
// please note that tRPC source code is licensed under the  Apache 2.0 License,
// A copy of the Apache 2.0 License is included in this file.
//
//

#pragma once

#include <memory>
#include <string_view>

#include "trpc/runtime/threadmodel/common/msg_task.h"
#include "trpc/runtime/threadmodel/common/timer_task.h"
#include "trpc/util/function.h"

namespace trpc {

/// @brief Base class for implement a scheduler using in separate thread model
class SeparateScheduling {
 public:
  virtual ~SeparateScheduling() = default;

  /// @brief get the pointer of scheduler in current thread
  static SeparateScheduling* GetCurrentScheduling() { return current_scheduling_; }

  /// @brief set the pointer of scheduler in current thread
  static void SetCurrentScheduling(SeparateScheduling* scheduling) { current_scheduling_ = scheduling; }

  /// @brief get id index of current worker thread
  static std::size_t GetCurrentWorkerIndex() { return current_worker_index_; }

  /// @brief set id index of current worker thread
  static void SetCurrentWorkerIndex(std::size_t worker_index) { current_worker_index_ = worker_index; }

  /// @brief name of the scheduler
  virtual std::string_view Name() const = 0;

  /// @brief pre action when enter current scheduler
  virtual void Enter(int32_t current_worker_thread_id) noexcept = 0;

  /// @brief task scheduling action for worker thread
  virtual void Schedule() noexcept = 0;

  /// @brief execute tasks in the queue, currently used to integrate with the taskflow ecosystem.
  ///        so that executing dynamic graphs does not block the current thread.
  virtual void ExecuteTask(std::size_t worker_index) noexcept = 0;

  /// @brief post action when leave current scheduler
  virtual void Leave() noexcept = 0;

  /// @brief submit io task
  /// @param io_task io task
  /// @return true if success, false if failed
  /// @note task must be generated by the object pool
  virtual bool SubmitIoTask(MsgTask* io_task) noexcept = 0;

  /// @brief submit handle task
  /// @param handle_task handle task
  /// @return true if success, false if failed
  /// @note task must be generated by the object pool
  virtual bool SubmitHandleTask(MsgTask* handle_task) noexcept = 0;

  virtual uint64_t AddTimer(TimerTask* timer_task) noexcept { return kInvalidTimerId; }
  virtual void PauseTimer(uint64_t timer_id) noexcept {}
  virtual void ResumeTimer(uint64_t timer_id) noexcept {}
  virtual void CancelTimer(uint64_t timer_id) noexcept {}
  virtual void DetachTimer(uint64_t timer_id) noexcept {}

  virtual void Stop() noexcept = 0;

  virtual void Destroy() noexcept = 0;

 private:
  static inline thread_local SeparateScheduling* current_scheduling_ = nullptr;
  static inline thread_local std::size_t current_worker_index_ = -1;
};

using SeparateSchedulingCreateFunction = Function<std::unique_ptr<SeparateScheduling>()>;

constexpr std::string_view kNonStealScheduling = "non_steal";

constexpr std::string_view kStealScheduling = "steal";

bool RegisterSeparateSchedulingImpl(const std::string& name, SeparateSchedulingCreateFunction&& func);

std::unique_ptr<SeparateScheduling> CreateSeparateScheduling(const std::string& name);

}  // namespace trpc
